package cn.itcast.nems.journal.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.itcast.ic.common.bean.Page;
import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.nems.approval.bpm.eventstrategy.BpmEventStrategy;
import cn.itcast.nems.approval.dao.entity.ApprovalForm;
import cn.itcast.nems.approval.enumeration.ApprovalFormStateEnum;
import cn.itcast.nems.approval.service.ApprovalFormFlowService;
import cn.itcast.nems.approval.service.ApprovalFormService;
import cn.itcast.nems.base.api.ClazzApi;
import cn.itcast.nems.base.dao.entity.E2Clazz;
import cn.itcast.nems.base.dao.mapper.E2ClazzMapper;
import cn.itcast.nems.base.dto.ClazzDTO;
import cn.itcast.nems.base.service.DictionaryService;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.common.account.AccountInfo;
import cn.itcast.nems.common.enumeration.BizNumberTypeEnum;
import cn.itcast.nems.common.enumeration.NemsErrorBodyEnum;
import cn.itcast.nems.common.service.BizNumberService;
import cn.itcast.nems.common.util.NumberUtil;
import cn.itcast.nems.common.utils.BigDecimalUtil;
import cn.itcast.nems.common.utils.WrapperUtil;
import cn.itcast.nems.journal.dto.JournalDropoutCreateDTO;
import cn.itcast.nems.journal.enumeration.JournalDiscountState;
import cn.itcast.nems.journal.enumeration.JournalStateEnum;
import cn.itcast.nems.journal.service.JournalDropoutService;
import cn.itcast.nems.journal.service.JournalRefundService;
import cn.itcast.nems.oldems.dto.oldapi.EmsApiResult;
import cn.itcast.nems.oldems.service.sync.OldEmsSyncService;
import cn.itcast.nems.order.dao.entity.OrderRefund;
import cn.itcast.nems.order.dto.JournalDropoutDTO;
import cn.itcast.nems.order.dto.OrderRefundDTO;
import cn.itcast.nems.order.service.OrderRefundService;
import cn.itcast.nems.studentrecord.constant.ReferenceTypeEnum;
import cn.itcast.nems.studentrecord.constant.RefundTypeEnum;
import cn.itcast.nems.studentrecord.dao.condition.ApprovalType;
import cn.itcast.nems.studentrecord.dao.condition.JournalDropoutParams;
import cn.itcast.nems.studentrecord.dao.condition.ReceivableAdjustmentState;
import cn.itcast.nems.studentrecord.dao.dataobject.JournalDropoutDO;
import cn.itcast.nems.studentrecord.dao.entity.JournalDropout;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecord;
import cn.itcast.nems.studentrecord.dao.mapper.JournalDropoutMapper;
import cn.itcast.nems.studentrecord.dto.SettlementResultDTO;
import cn.itcast.nems.studentrecord.dto.change.StudentRecordJournalDropoutDTO;
import cn.itcast.nems.studentrecord.dto.refund.JournalRefundDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentTotalRefundableAmountDTO;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordErrorBodyEnum;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordStateEnum;
import cn.itcast.nems.studentrecord.service.StudentRecordDropoutService;
import cn.itcast.nems.studentrecord.service.settlement.SettlementCalculator;
import cn.itcast.nems.studentrecord.service.settlement.SettlementCalculatorDropout;
import cn.itcast.nems.studentrecord.service.settlement.SettlementData;
import cn.itcast.nems.studentrecord.service.settlement.SettlementResult;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordFundFlowService;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.itcast.nems.journal.util.TransferUtils.formatPrice;

/**
 * <p>
 * 退学凭单-头 服务实现类
 * </p>
 *
 * @author 陈早庆
 * @since 2023-12-07
 */
@Slf4j
@Service
public class JournalDropoutServiceImpl extends ServiceImpl<JournalDropoutMapper, JournalDropout> implements JournalDropoutService, BpmEventStrategy {
    @Autowired
    private ApprovalFormService approvalFormService;
    @Autowired
    private ApprovalFormFlowService approvalFormFlowService;
    @Autowired
    private ClazzApi clazzApi;
    @Autowired
    private E2ClazzMapper e2ClazzMapper;
    @Autowired
    private StudentRecordService studentRecordService;
    @Autowired
    private OrderRefundService orderRefundService;
    @Autowired
    private BizNumberService bizNumberService;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private StudentRecordDropoutService studentRecordDropoutService;
    @Autowired
    private OldEmsSyncService oldEmsSyncService;
    @Autowired
    private StudentRecordFundFlowService fundFlowService;
    @Autowired
    private JournalRefundService journalRefundService;
    @Autowired
    private static final BigDecimal DENOMINATOR = new BigDecimal("100");

    /**
     * 取退学原因列表的字典父级CODE：NEMS_JOURNAL_DROPOUT_REASON
     */
    private static final String DICT_DROPOUT_REASON = "NEMS_JOURNAL_DROPOUT_REASON";
    /**
     * 取退学办理时公司列表的字典父级CODE：NEMS_COMPANY
     */
    private static final String DICT_DROPOUT_COMPANY = "NEMS_COMPANY";

    /**
     * 获取我提交的、待办凭单、已办凭单、全部凭单
     *
     * @param pageNumber
     * @param pageSize
     * @param params
     * @return
     */
    @Override
    public Page<JournalDropoutDO> listPage(Integer pageNumber, Integer pageSize, JournalDropoutParams params) {
        ApprovalType approvalType = params.getApprovalType();
        if (approvalType == ApprovalType.ALL) {
            if (!AccountHolder.hasEmployeeGroups()) {
                return Page.of(pageNumber, pageSize, 0, null);
            }
            params.setEmployeeGroups(AccountHolder.getEmployeeGroups());
        }
        listPageParams(params);
        IPage<JournalDropoutDO> pageData = baseMapper.listPage(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNumber, pageSize), params);
        if (CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        return Page.of(pageNumber, pageSize, (int) pageData.getTotal(), pageData.getRecords());
    }

    @Override
    public Page<Map> searchClazzes(Integer pageNumber, Integer pageSize, JournalDropoutParams params) {
        ApprovalType approvalType = params.getApprovalType();
        if (approvalType == ApprovalType.ALL) {
            if (!AccountHolder.hasEmployeeGroups()) {
                return Page.of(pageNumber, pageSize, 0, null);
            }
            params.setEmployeeGroups(AccountHolder.getEmployeeGroups());
        }
        listPageParams(params);
        IPage<Map> pageData = baseMapper.searchClazzes(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNumber, pageSize), params);
        if (CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        return Page.of(pageNumber, pageSize, (int) pageData.getTotal(), pageData.getRecords());
    }

    @Override
    public JournalDropout queryByStudentRecordId(String studentRecordId) {
        return getBaseMapper().selectOne(new WrapperUtil<JournalDropout>()
                .limitLaseOne("created_datetime")
                .eq(JournalDropout::getStudentRecordId, studentRecordId)
                .eq(JournalDropout::getState, ApprovalFormStateEnum.FINISHED.name())
                .eq(JournalDropout::getDeletedFlag, Boolean.FALSE));
    }

    private void listPageParams(JournalDropoutParams params) {
        ApprovalType approvalType = params.getApprovalType();
        params.setJournalType(ApprovalFormService.JournalType.DROPOUT.name());
        if (approvalType == ApprovalType.MY_COMMIT) {
            // 我提交的
            params.setFlowCreatedBy(AccountHolder.getRequiredAccount());
            params.setCreatedBy(AccountHolder.getRequiredAccount());
        } else if (approvalType == ApprovalType.WAIT_APPROVAL) {
            // 待办凭单
            List<String> journalIdFormIds = approvalFormService.getJournalIdFormIds(ApprovalFormService.JournalType.DROPOUT);
            if (CollectionUtil.isNotEmpty(journalIdFormIds)) {
                params.setFormIds(journalIdFormIds);
            }
            params.setFlowCreatedBy(AccountHolder.getRequiredAccount());
            params.setExcludeState(ReceivableAdjustmentState.DRAFT.name());
        } else if (approvalType == ApprovalType.APPROVED) {
            // 已办凭单
            List<String> journalIdFormIds = approvalFormService.getJournalIdFormIds(ApprovalFormService.JournalType.DROPOUT);
            if (CollectionUtil.isNotEmpty(journalIdFormIds)) {
                params.setFormIds(journalIdFormIds);
            }
            params.setFlowCreatedBy(AccountHolder.getRequiredAccount());
            params.setExcludeState(ReceivableAdjustmentState.DRAFT.name());
        } else if (approvalType == ApprovalType.ALL) {
            // 全部凭单
            params.setExcludeState(ReceivableAdjustmentState.DRAFT.name());
        }
    }

//    public JournalDropoutDO convert(JournalDropoutDO journalDropoutDO, List<String> waitApprovalJournalIds) {
//        String id = journalDropoutDO.getId();
//        Boolean needApproval = Boolean.TRUE;
//        if (CollectionUtil.isNotEmpty(waitApprovalJournalIds) && waitApprovalJournalIds.contains(id)) {
//            journalDropoutDO.setNeedApproval(needApproval);
//        }
//        ApprovalForm approvalForm = approvalFormService.getOne(new LambdaQueryWrapper<ApprovalForm>().eq(ApprovalForm::getJournalId, id)
//                .eq(ApprovalForm::getDeletedFlag, Boolean.FALSE)
//                .notIn(ApprovalForm::getState, ApprovalFormStateEnum.CANCELED.name()).last(" order by created_datetime desc limit 1"));
//        journalDropoutDO.setFormId(Objects.nonNull(approvalForm) ? approvalForm.getId() : null);
//        return journalDropoutDO;
//    }

    @Override
    public JournalDropout getById(String id) {
        return baseMapper.selectById(id);
    }

    @Override
    public JournalDropoutDO getJournalDropoutById(String id) {
        JournalDropoutDO journalDropoutDO = baseMapper.getJournalDropoutById(id);
        List<ApprovalForm> myApprovedForms = this.approvalFormService.getMyApprovedForms(ApprovalFormService.JournalType.DROPOUT, AccountHolder.getRequiredAccountInfo().getEmail());
        if (CollectionUtil.isNotEmpty(myApprovedForms)) {
            List<String> waitApprovalJournalIds = myApprovedForms.stream().map(ApprovalForm::getJournalId).collect(Collectors.toList());
//            convert(journalDropoutDO, waitApprovalJournalIds);
            Boolean needApproval = Boolean.TRUE;
            if (CollectionUtil.isNotEmpty(waitApprovalJournalIds) && waitApprovalJournalIds.contains(id)) {
                journalDropoutDO.setNeedApproval(needApproval);
            }
            ApprovalForm approvalForm = approvalFormService.getOne(new LambdaQueryWrapper<ApprovalForm>().eq(ApprovalForm::getJournalId, id)
                    .eq(ApprovalForm::getDeletedFlag, Boolean.FALSE)
                    .notIn(ApprovalForm::getState, ApprovalFormStateEnum.CANCELED.name()).last(" order by created_datetime desc limit 1"));
            journalDropoutDO.setFormId(Objects.nonNull(approvalForm) ? approvalForm.getId() : null);
        } else {
            ApprovalForm approvalForm = approvalFormService.getOne(new LambdaQueryWrapper<ApprovalForm>().eq(ApprovalForm::getJournalId, id)
                    .eq(ApprovalForm::getDeletedFlag, Boolean.FALSE)
                    .notIn(ApprovalForm::getState, ApprovalFormStateEnum.CANCELED.name()).last(" order by  created_datetime desc limit 1"));
            journalDropoutDO.setFormId(Objects.nonNull(approvalForm) ? approvalForm.getId() : null);
        }
        if (journalDropoutDO.getClazzId() != null) {
            ClazzDTO clazzDTO = clazzApi.queryByClassId(journalDropoutDO.getClazzId());
            if (clazzDTO != null) {
                journalDropoutDO.setStartDate(clazzDTO.getStartDate());
                journalDropoutDO.setPredictionGraduationDate(clazzDTO.getPredictionGraduationDate());
                // TODO 区分ApprovalType，待我审批、已办事项不限制数据权限
//                Assert.isFalse(!AccountHolder.hasEmployeeGroups(clazzDTO.getSchoolId(), clazzDTO.getSubjectId()), BizExceptionProducer.unauthorized("暂无权限"));
            }
        }
        return journalDropoutDO;
    }

    @Override
    @Transactional
    public String create(JournalDropoutDTO params) {
        String studentRecordId = params.getStudentRecordId();
        StudentRecord studentRecord = studentRecordService.getById(studentRecordId);
        Assert.notNull(studentRecord, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "该学籍不存在，请刷新后重新办理！"));
        Assert.isTrue(!studentRecord.getLockFlag(), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.STUDENT_RECORD_LOCKED));

        JournalDropout journalDropout = new JournalDropout();
        BeanUtils.copyProperties(params, journalDropout);
        if (params.getAmount() != null) {
            Integer amount = BigDecimalUtil.bigDecimalToCentInt(params.getAmount().setScale(2, RoundingMode.HALF_UP));
            journalDropout.setAmount(amount);
        } else {
            journalDropout.setAmount(0);
        }

        journalDropout.setId(bizNumberService.next(BizNumberTypeEnum.JOURNAL_DROPOUT));
        journalDropout.setClazzId(studentRecord.getClazzId());
        journalDropout.setClazzName(studentRecord.getClazzName());

        // 退学结算
        settlementCalculatorRefund(params, journalDropout);

        // 退学原因说明
        if (StringUtils.hasText(params.getReasonCode())) {
            String reasonDescription = dictionaryService.getNameByParentCode(DICT_DROPOUT_REASON, params.getReasonCode());
            journalDropout.setReasonDescription(reasonDescription);
        }

        // 所属公司名称
        if (StringUtils.hasText(params.getCompanyCode())) {
            String companyName = dictionaryService.getNameByParentCode(DICT_DROPOUT_COMPANY, params.getCompanyCode());
            journalDropout.setCompanyName(companyName);
        }

        if (!StringUtils.hasText(journalDropout.getRemark())) {
            journalDropout.setRemark("");
        }

        // 退费金额 用户录入不做计算
        // 添加退学凭单
        int insert = baseMapper.insert(journalDropout);
        Assert.isTrue(insert > 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "创建失败"));
        // 不是草稿并且是提交启动流程
        if (!JournalStateEnum.DRAFT.name().equals(journalDropout.getState()) && JournalStateEnum.PENDING.name().equals(journalDropout.getState())) {
            // 启动流程
            this.startProcess(journalDropout);
        }
        return journalDropout.getId();
    }

    @Override
    public Boolean delete(String id) {
        var journal = baseMapper.selectById(id);
        Assert.notNull(journal, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "ID：" + id));
        Assert.isTrue(JournalStateEnum.DRAFT.name().equalsIgnoreCase(journal.getState()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.WORKFLOW_NO_DRAFT_DELETE));
        Assert.isTrue(journal.getCreatedBy().equals(AccountHolder.getRequiredAccount()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "只能删除自己创建的数据"));
        // 解锁学籍
        studentRecordService.unlock(journal.getStudentRecordId());
        return lambdaUpdate().eq(JournalDropout::getId, id)
                .set(JournalDropout::getDeletedBy, AccountHolder.getRequiredAccount())
                .set(JournalDropout::getDeletedDatetime, LocalDateTime.now())
                .set(JournalDropout::getDeletedFlag, Boolean.TRUE).update();
    }

    @Override
    @Transactional
    public Boolean update(JournalDropoutDTO params) {
        // 仅支持草稿修改
        // 检查数据是否存在，并且状态合理
        JournalDropout journalDropoutById = baseMapper.selectById(params.getId());
        Assert.notNull(journalDropoutById, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "该凭单不存在，请刷新后重新办理！"));

        // 校验退学学籍是否存在
        StudentRecord studentRecord = this.getAndcheckDropoutStudentRecord(params.getStudentRecordId());

//        Boolean exists = exists(params.getId(), studentRecordId, params.getClazzId());
//        Assert.isTrue(!exists, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "凭单已存在"));
        JournalDropout journalDropout = new JournalDropout();
        BeanUtils.copyProperties(params, journalDropout);
        journalDropout.setState(Boolean.TRUE.equals(params.getDraftFlag()) ? JournalStateEnum.DRAFT.name() : JournalStateEnum.PENDING.name());
        Assert.isTrue(List.of("DRAFT", "PENDING", "COMMIT").contains(journalDropout.getState()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "只能存为草稿或提交"));
        if (params.getAmount() != null) {
            Integer amount = BigDecimalUtil.bigDecimalToCentInt(params.getAmount().setScale(2, RoundingMode.HALF_UP));
            journalDropout.setAmount(amount);
            studentRecordService.validateAmount(studentRecord, amount, journalDropout.getState());
        } else {
            journalDropout.setAmount(0);
        }
        Integer clazzId = params.getClazzId();
        // 根据班级id获取name
        ClazzDTO clazzDTO = clazzApi.queryByClassId(clazzId);
        if (clazzDTO != null) {
            journalDropout.setClazzName(clazzDTO.getClassName());
        }
        settlementCalculatorRefund(params, journalDropout);
        // 退学原因说明
        String reasonDescription = dictionaryService.getNameByParentCode(DICT_DROPOUT_REASON, params.getReasonCode());
        journalDropout.setReasonDescription(reasonDescription);
        // 所属公司名称
        String companyName = dictionaryService.getNameByParentCode(DICT_DROPOUT_COMPANY, params.getCompanyCode());
        journalDropout.setCompanyName(companyName);
        // 退学前，先结清欠费。有欠费的情况下，不可以办理退学业务。
//        Assert.isTrue(studentRecord.getBalanceAmountDue() <= 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, String.format("办理退学失败！当前该学生尚有欠费%s元，请提醒学员缴清欠费后再办理退学。", formatPrice(studentRecord.getBalanceAmountDue()))));
        if (!StringUtils.hasText(journalDropout.getRemark())) {
            journalDropout.setRemark("");
        }
        int updateById = baseMapper.updateById(journalDropout);
        Assert.isTrue(updateById > 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "创建失败"));
        // 不是草稿并且是提交启动流程
        if (!JournalStateEnum.DRAFT.name().equals(journalDropout.getState()) && JournalStateEnum.PENDING.name().equals(journalDropout.getState())) {
            // 启动流程
            this.startProcess(journalDropout);
        }
        return Boolean.TRUE;
    }

    private void settlementCalculatorRefund(JournalDropoutDTO params, JournalDropout journalDropout) {
        this.settlementCalculatorRefund(params.getStudentRecordId(), params.getBizDate().toLocalDate(), params.getType(), journalDropout);
    }

    private void settlementCalculatorRefund(final String studentRecordId, final LocalDate bizDate, final String type, JournalDropout journalDropout) {
        // 退学结算
        SettlementResultDTO settlementResultDTO = this.settlementCalculatorRefund(studentRecordId, bizDate, type);

        // 实际应付金额
        if (StringUtils.hasText(settlementResultDTO.getActualAmountDue())) {
            journalDropout.setActualAmountDue(Integer.valueOf(settlementResultDTO.getActualAmountDue()));
        } else {
            journalDropout.setActualAmountDue(0);
        }

        // 应服务天数
        journalDropout.setServiceDays(settlementResultDTO.getServiceDays());
        // 实际服务天数
        journalDropout.setSettlementDays(settlementResultDTO.getSettlementDays());
        // 课耗金额
        if (StringUtils.hasText(settlementResultDTO.getSettlementAmount())) {
            journalDropout.setSettlementAmount(Integer.valueOf(settlementResultDTO.getSettlementAmount()));
        } else {
            journalDropout.setSettlementAmount(0);
        }

        // 校验本次退费金额是否超过学生最大可退费金额
        checkoutRefundableAmount(studentRecordId, journalDropout.getAmount());

        // 已交金额
        journalDropout.setPaidAmount(Integer.valueOf(settlementResultDTO.getPaidAmount()));

        // 剩余金额
        if (StringUtils.hasText(settlementResultDTO.getSettlementArrearsAmount())) {
            journalDropout.setSettlementBalanceAmount(Integer.valueOf(settlementResultDTO.getSettlementArrearsAmount()));
        } else {
            journalDropout.setSettlementBalanceAmount(0);
        }

        // 退费金额（过往退费金额）;来自于学籍，不算本次退费金额。
        if (StringUtils.hasText(settlementResultDTO.getRefundAmount())) {
            journalDropout.setRefundAmount(Integer.valueOf(settlementResultDTO.getRefundAmount()));
        } else {
            journalDropout.setRefundAmount(0);
        }

        // 转班转入金额;来自于学籍。非转班该字段金额为零
        if (StringUtils.hasText(settlementResultDTO.getTransferFromAmount())) {
            journalDropout.setTransferFromAmount(Integer.valueOf(settlementResultDTO.getTransferFromAmount()));
        } else {
            journalDropout.setTransferFromAmount(0);
        }
    }

    /**
     * 功能描述：校验本次退费金额是否超过最大可退费金额
     *
     * @param studentRecordId 学籍ID
     * @param refundAmount    本次退费金额
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2024年3月19日
     */
    private void checkoutRefundableAmount(final String studentRecordId, final Integer refundAmount) {
        if (Objects.isNull(refundAmount) || refundAmount == 0) {
            return;
        }

        Integer studentId = studentRecordService.getStudentIdByID(studentRecordId);
        Assert.isTrue(Objects.nonNull(studentId) && studentId > 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.STUDENT_RECORD_DATA_EXCEPTION_STUDENT_ID));
        // 获取学生最大可退费金额（基于学生维度判断而不是学籍维度）
        StudentTotalRefundableAmountDTO studentTotalRefundableAmountDTO = fundFlowService.getStudentTotalRefundableAmountDTO(studentId);
        Assert.notNull(studentTotalRefundableAmountDTO, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.REFUNDABLE_AMOUNT_DATA_EXCEPTION));

        Assert.isTrue(refundAmount <= studentTotalRefundableAmountDTO.getTotalRefundableAmount(),
                BizExceptionProducer.produce(StudentRecordErrorBodyEnum.DROPOUT_OUT_OF_REFUNDABLE_AMOUNT, formatPrice(studentTotalRefundableAmountDTO.getTotalRefundableAmount())));
    }

    // 启动流程
    private String startProcess(JournalDropout params) {
        // 锁定学籍
        studentRecordService.locks(Set.of(params.getStudentRecordId()), ReferenceTypeEnum.DROPOUT, params.getId());
        String id = params.getId();
        HashMap<String, Object> variables = new HashMap<>();
//      1、是否需要退费  is_refund_needed （"true"， "false"）
        variables.put("is_refund_needed", params.getType().equals(RefundTypeEnum.DROPOUT_REFUND.name()) ? "true" : "false");
//      2、是否特殊审批  special_approval （"true"， "false"）
        variables.put("special_approval", String.valueOf(params.getSpecialFlag()));
//      3、经手部门  handling_department （“发起人部门”）
        variables.put("handling_department", "发起人部门");
//      5、授课模式  teaching_model （"FACETOFACE" ）   # EMS授课模式编码
        Integer clazzId = params.getClazzId();
        E2Clazz e2Clazz = e2ClazzMapper.selectOne(new QueryWrapper<E2Clazz>().lambda().eq(E2Clazz::getClazzId, clazzId));
        if (e2Clazz != null) {
//      4、目标班级校区名称  target_clazz_school_name（"BEIJING"）
            variables.put("target_clazz_school_name", e2Clazz.getSchoolCode());
            variables.put("teaching_model", e2Clazz.getTeachingModel());
        }
//      6、退费金额  refund_amount （70000） # 单位：分
        variables.put("refund_amount", String.valueOf(params.getAmount()));
//      7、是否是贷款  is_loan （"true"， "false"）
        variables.put("is_loan", String.valueOf(params.getLoanFlag()));
//      8、是否开发票  is_invoice_included （"true"， "false"）
        variables.put("is_invoice_included", String.valueOf(params.getInvoiceFlag()));
//      9、NC公司编码 nc_company_code （“0101”） # NC公司编码
        // 所属公司code
        variables.put("nc_company_code", params.getCompanyCode());
        // 来源校区校长
//        variables.put("origin_campus", "");
        String start = approvalFormService.start(ApprovalFormService.JournalType.DROPOUT, id, variables, null);
        log.info("【提交】流程审批单详情：{}", start);
        return start;
    }


    /**
     * 1、“应交金额”，取值 “实际应交金额”
     * 2、“应服务天数”，计算公式：学籍预计结课日期 - 学籍开班日期 + 1
     * 3、“实际服务天数”，计算公式：退学日期 -  学籍入班日期 + 1
     * 4、“课耗金额”，计算公式：应交金额/应付天数 * 实际服务天数
     * 5、“已交金额”，取值：已交金额 + 转班转入金额 - 已退费合计
     * 6、“剩余金额”，计算公式：已交金额 - 课耗金额
     *
     * @param studentRecordId 学籍id
     * @param settlementDate  出班结算日期
     * @param type
     * @return
     */
    @Override
    public SettlementResultDTO settlementCalculatorRefund(String studentRecordId, LocalDate settlementDate, String type) {
        StudentRecord studentRecord = studentRecordService.getById(studentRecordId);
        Assert.notNull(studentRecord, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "学籍ID：" + studentRecordId));
        ClazzDTO clazzDTO = clazzApi.queryByClassId(studentRecord.getClazzId());
        Assert.notNull(clazzDTO, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.BAD_REQUEST, "学籍ID：" + clazzDTO.getClassId()));
        SettlementData settlementData = new SettlementData();
        settlementData.setClazzId(clazzDTO.getClassId());
        settlementData.setPrice(studentRecord.getPrice());
        settlementData.setAmountDue(studentRecord.getAmountDue());
        settlementData.setActualAmountDue(studentRecord.getActualAmountDue());
        settlementData.setPaidAmount(studentRecord.getPaidAmount());
        settlementData.setRefundAmount(studentRecord.getRefundAmount());
        settlementData.setStartDate(clazzDTO.getStartDate());
        settlementData.setPredictionGraduationDate(clazzDTO.getPredictionGraduationDate());
        settlementData.setInDate(studentRecord.getInDate());
        settlementData.setSettlementDate(settlementDate.atStartOfDay());
        settlementData.setTransferFromAmount(studentRecord.getTransferFromAmount());
        settlementData.setDelayFlag(clazzDTO.getDelayFlag());
        settlementData.setSuspensionFlag(clazzDTO.getSuspensionFlag());
        SettlementCalculator calculator = new SettlementCalculatorDropout();
        SettlementResult calculate = calculator.calculate(settlementData);
        SettlementResultDTO settlementResultDTO = new SettlementResultDTO();
        BeanUtils.copyProperties(calculate, settlementResultDTO);
        if (calculate.getSettlementAmount() != null) {
            settlementResultDTO.setSettlementAmount(String.valueOf(calculate.getSettlementAmount()));
        }
        // 应交金额
        if (studentRecord.getActualAmountDue() != null) {
            settlementResultDTO.setActualAmountDue(String.valueOf(studentRecord.getActualAmountDue()));
        }
        // 已交金额
        // paid_amount+transfer_from_amount-refund_amount-transfer_out_amount
        // 公式：已交金额 + 转班转入金额 - 已退费合计
        int amount = studentRecord.getPaidAmount()
                + studentRecord.getTransferFromAmount()
                - studentRecord.getRefundAmount();
        if (studentRecord.getTransferOutAmount() != null) {
            amount = amount - studentRecord.getTransferOutAmount();
        }
        amount = Math.max(amount, 0);
        settlementResultDTO.setPaidAmount(String.valueOf(amount));
        // 学籍已交金额
        settlementResultDTO.setStudentRecordPaidAmount(studentRecord.getPaidAmount());
        if (studentRecord.getRefundAmount() != null) {
            settlementResultDTO.setRefundAmount(String.valueOf(studentRecord.getRefundAmount()));
        }
        // 转班转入金额
        if (studentRecord.getTransferFromAmount() != null) {
            settlementResultDTO.setTransferFromAmount(String.valueOf(studentRecord.getTransferFromAmount()));
        }
        // 剩余金额
        // 公式：已付金额 - 课耗金额
        if (calculate.getSettlementAmount() != null) {
            int settlementBalanceAmount = Math.max(amount - calculate.getSettlementAmount(), 0);
            settlementResultDTO.setSettlementArrearsAmount(String.valueOf(settlementBalanceAmount));
        }
        return settlementResultDTO;
    }


    @Override
    @Transactional
    public Boolean flow(String id) {
        JournalDropout journalDropout = getById(id);
        log.info("【提交】根据ID查询凭单头 ，ID：{}，查询结果：{}", id, JSON.toJSONString(journalDropout));
        Assert.isTrue(JournalStateEnum.DRAFT.name().equalsIgnoreCase(journalDropout.getState()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.REQUEST_JOURNAL_RENEWAL_STATE_ERROR));
        if (journalDropout.getAmount() != null) {
            StudentRecord studentRecord = this.getAndcheckDropoutStudentRecord(journalDropout.getStudentRecordId());
            Integer amount = journalDropout.getAmount();
            studentRecordService.validateAmount(studentRecord, amount, JournalStateEnum.PENDING.name());
        }
        String result = this.startProcess(journalDropout);
        log.info("【提交】流程审批单详情：{}", result);
        return lambdaUpdate().eq(JournalDropout::getId, id).set(JournalDropout::getState, JournalStateEnum.PENDING.name()).update();
    }

    @Override
    public Boolean exists(String id, String studentRecordId, Integer clazzId) {
        return lambdaQuery()
                .eq(JournalDropout::getStudentRecordId, studentRecordId)
                .eq(JournalDropout::getClazzId, clazzId)
                // 过滤掉修改本身
                .ne(JournalDropout::getState, ApprovalFormStateEnum.REJECTED.name())
                .ne(StringUtils.hasText(id), JournalDropout::getId, id)
                .exists();
    }

    @Override
    @Transactional
    public String getStrategyName() {
        return ApprovalFormService.JournalType.DROPOUT.name();
    }

    @Override
    @Transactional
    public void inform(String formID, String targetAssignee) {
        approvalFormFlowService.inform(formID, targetAssignee);
    }

    @Transactional
    @Override
    public Runnable finish(String formID) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            return null;
        }

        String journalId = approvalForm.getJournalId();
        log.info("【审批流程所有节点全部审批通过】查询审批单详情：{}", JSON.toJSONString(approvalForm));
        JournalDropout journal = getById(journalId);
        if (journal.getState().equals(JournalStateEnum.FINISHED.name())) {
            log.info("【审批流程所有节点全部审批通过】已通过状态无需处理，ID：{}", journalId);
            return null;
        }
        log.info("【审批流程所有节点全部审批通过】查询凭单详情：{}", JSON.toJSONString(journal));
        // TODO 同步老EMS
        ApprovalFormStateEnum approvalFormStateEnum = ApprovalFormStateEnum.FINISHED;
        EmsApiResult dropout = oldEmsSyncService.dropout(journal.getStudentRecordId(), journal.getBizDate().toLocalDate(), journal.getType(), journal.getCreatedBy());
        if (!dropout.isSuccess()) {
            approvalFormStateEnum = ApprovalFormStateEnum.APPROVING;
        }
        // 处理凭单的审批状态
        lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getState, approvalFormStateEnum.name()).update();
        log.info("【审批流程所有节点全部审批通过】修改状态 ID：{}， 修改状态：{}", journalId, approvalFormStateEnum.name());
        if (approvalFormStateEnum == ApprovalFormStateEnum.FINISHED) {
            // 处理本地的审批流程单
            approvalFormService.finish(formID);
        } else {
            // 失败
            approvalFormService.fail(formID, dropout.getErrorMessage());
            return null;
        }

        StudentRecordJournalDropoutDTO studentRecordJournalDropout = new StudentRecordJournalDropoutDTO();
//        if (RefundTypeEnum.DROPOUT_REFUND.name().equals(journalDropout.getType())) {
//            // 退学且退费-添加退单
//            OrderRefund orderRefund = createDropoutRefund(journalDropout, journalId);
//            String orderRefundId = orderRefund.getId();
//            String orderRefundLineId = orderRefund.getOrderRefundLineId();
//            if (orderRefund != null && orderRefundId != null) {
//                // 3.修改退学凭单表，退费凭单ID;只有在“退学退费”时才会产生
//                lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getJournalRefundId, orderRefundId).update();
//                studentRecordJournalDropout.setRefundJournalId(orderRefundId);
//                studentRecordJournalDropout.setRefundJournalLineId(orderRefundLineId);
//            }
//        }
        // 退学相关逻辑
        studentRecordJournalDropout.setType(RefundTypeEnum.DROPOUT);
        studentRecordJournalDropout.setJournalId(journalId);
        studentRecordJournalDropout.setJournalLineId(journalId);
        studentRecordJournalDropout.setStudentRecordId(journal.getStudentRecordId());
        studentRecordJournalDropout.setClazzId(journal.getClazzId());
        studentRecordJournalDropout.setClazzName(journal.getClazzName());
        studentRecordJournalDropout.setClazzOutDate(journal.getBizDate());
        studentRecordJournalDropout.setClazzServiceDays(journal.getServiceDays());
        studentRecordJournalDropout.setClazzSettlementDays(journal.getSettlementDays());
        studentRecordJournalDropout.setClazzSettlementAmount(journal.getSettlementAmount());
        studentRecordJournalDropout.setAmount(journal.getAmount());
        log.info("【退学相关逻辑】{}", JSON.toJSONString(studentRecordJournalDropout));
        studentRecordDropoutService.dropout(studentRecordJournalDropout);
        // 如果退学类型为 ”退学退费“ ， 需要生成退费凭单
        if (RefundTypeEnum.DROPOUT_REFUND.name().equals(journal.getType())) {
            JournalRefundDTO journalRefundDTO = this.wrapJournalRefundDTO(journal);
            journalRefundDTO.setState(JournalStateEnum.PENDING.name());
            log.info("【退学退费发起退费凭单】 参数：{}", JSON.toJSONString(journalRefundDTO, SerializerFeature.DisableCircularReferenceDetect));
            String journalRefundId = journalRefundService.create(journalRefundDTO);
            log.info("【退学退费发起退费凭单】新生成退费凭单ID：{}", journalRefundId);
            lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getJournalRefundId, journalRefundId).update();
        }
        return null;
    }

    @Override
    public void testFinishRefund(String formId) {
        this.finish(formId);
//        JournalDropout journal = getById(journalId);
//        Assert.notNull(journal,"未找到凭单");
//        if (RefundTypeEnum.DROPOUT_REFUND.name().equals(journal.getType())) {
//            JournalRefundDTO journalRefundDTO = this.wrapJournalRefundDTO(journal);
//            journalRefundDTO.setState(JournalStateEnum.PENDING.name());
//            log.info("【退学退费发起退费凭单】 参数：{}", JSON.toJSONString(journalRefundDTO, SerializerFeature.DisableCircularReferenceDetect));
//            journalRefundService.create(journalRefundDTO);
//        }
    }

    private JournalRefundDTO wrapJournalRefundDTO(JournalDropout dropout) {
        JournalRefundDTO journalRefundDTO = new JournalRefundDTO();
        journalRefundDTO.setState(ApprovalFormStateEnum.PENDING.name());
        journalRefundDTO.setStudentRecordId(dropout.getStudentRecordId());
        journalRefundDTO.setAmount(NumberUtil.convertToYuan(dropout.getAmount()));
        journalRefundDTO.setRefundTypeId(baseMapper.studentCostTypesByName("退费-学费"));
        journalRefundDTO.setBizDate(dropout.getBizDate());
        journalRefundDTO.setInvoiceFlag(dropout.getInvoiceFlag());
        journalRefundDTO.setInvoiceNo(null);
        journalRefundDTO.setRemark(dropout.getRemark());
        journalRefundDTO.setSpecialFlag(dropout.getSpecialFlag());
        journalRefundDTO.setReasonCode(dropout.getReasonCode());
        journalRefundDTO.setJournalDropoutId(dropout.getId());
        journalRefundDTO.setLoanFlag(dropout.getLoanFlag());
        return journalRefundDTO;
    }

    // 退学且退费-添加退单
    private OrderRefund createDropoutRefund(JournalDropout journalDropout, String journalId) {
        final AccountInfo info = AccountHolder.getRequiredAccountInfo();
        // 退学退费-流程审批完成自动生成：
        // 1.生成-退费单 e2_order_refund
        // 2.生成-学籍资金流转明细 e2_student_record_fund_flow
        OrderRefundDTO orderRefundDTO = new OrderRefundDTO();
        orderRefundDTO.setCreatedBy(info.getEmail());
        orderRefundDTO.setRefundOperatorEmail(info.getEmail());
        orderRefundDTO.setCreatedByName(info.getName());
        orderRefundDTO.setRefundOperatorName(info.getName());
        orderRefundDTO.setStudentRecordId(journalDropout.getStudentRecordId());
//      费用类型：培训收入、押金、电脑使用费、吸烟罚款、学生住宿费等。注：数据来自来自于数据字典
        orderRefundDTO.setCostTypeId(baseMapper.incomeexpensestypeByName("培训收入"));
//       退费类型：退报名费、退学费、退多交学费、退电脑使用费等。注：来自于数据字典
        orderRefundDTO.setRefundTypeId(baseMapper.studentCostTypesByName("退费-学费"));
        orderRefundDTO.setRefundDate(journalDropout.getBizDate().toLocalDate());
        orderRefundDTO.setAmount(BigDecimal.valueOf(journalDropout.getAmount()).divide(DENOMINATOR, 2, RoundingMode.HALF_UP));
        orderRefundDTO.setCharge(BigDecimal.ZERO);
        orderRefundDTO.setBizDate(journalDropout.getBizDate());
        orderRefundDTO.setReasonDescription(journalDropout.getRemark());
        orderRefundDTO.setClazzId(journalDropout.getClazzId());
        orderRefundDTO.setLoanFlag(journalDropout.getLoanFlag());
        orderRefundDTO.setSpecialFlag(journalDropout.getSpecialFlag());
        orderRefundDTO.setJournalType(ReferenceTypeEnum.DROPOUT);
        orderRefundDTO.setJournalId(journalId);
        return orderRefundService.createDropoutRefund(orderRefundDTO);
    }

    @Override
    public void approve(String formID, ApprovalFormService.ApproveResult result, String comment, final String form, Integer applyType) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            log.info("【审批完成】未匹配到数据：" + formID);
            return;
        }
        String journalId = approvalForm.getJournalId();
        JournalDropout journal = getById(journalId);
        log.info("【审批完成】查询审批单详情：{}", JSON.toJSONString(approvalForm));
        if (ApprovalFormService.ApproveResult.REJECT == result) {
            // 审批未通过
            lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getState, JournalStateEnum.REJECTED.name()).update();
            studentRecordService.unlock(journal.getStudentRecordId());
        } else {
            JournalStateEnum journalStateEnum = JournalStateEnum.APPROVING;
            //  1：审批（默认））2：驳回到发起人）3：驳回上一级）
            if (applyType != null && applyType == 2) {
                journalStateEnum = JournalStateEnum.DRAFT;
                studentRecordService.unlock(journal.getStudentRecordId());
            } else if (applyType != null && applyType == 3) {
                journalStateEnum = JournalStateEnum.PENDING;
            }
            // 审批通过-修改为审核中
            lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getState, journalStateEnum.name()).update();
        }
        approvalFormService.approve(formID, result, comment, form, applyType);
    }

    @Override
    @Transactional
    public void cancel(final String formID) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            log.info("【撤回】未匹配到数据：" + formID);
            return;
        }
        String journalId = approvalForm.getJournalId();
        JournalDropout journalDropout = this.getById(journalId);
        Assert.notNull(journalDropout, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "ID：" + formID));
        // 校验：必须发起人才能撤回
        org.springframework.util.Assert.isTrue(journalDropout.getCreatedBy().equals(AccountHolder.getRequiredAccount()), "必须发起人才能撤回");
        // 撤回-状态改为：草稿
        lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getState, JournalStateEnum.DRAFT.name()).update();
        approvalFormService.cancel(formID);
        // 解锁学籍
        studentRecordService.unlock(journalDropout.getStudentRecordId());
    }

    @Override
    @Transactional
    public void rollbackRequester(String formID) {
        ApprovalForm approvalForm = approvalFormService.getByBusinessKey(formID);
        if (approvalForm == null) {
            log.info("【撤回】未匹配到数据：" + formID);
            return;
        }
        String journalId = approvalForm.getJournalId();
        JournalDropout journalDropout = this.getById(journalId);
        Assert.notNull(journalDropout, BizExceptionProducer.produce(NemsErrorBodyEnum.DATA_EXIST, "ID：" + formID));
        if (journalDropout.getState().equals(JournalDiscountState.DRAFT.name())) {
            return;
        }
        // 撤回-状态改为：草稿
        lambdaUpdate().eq(JournalDropout::getId, journalId).set(JournalDropout::getState, JournalStateEnum.DRAFT.name()).update();
        // 解锁学籍
        studentRecordService.unlock(journalDropout.getStudentRecordId());
    }

    @Override
    public void remind(String formID, String targetAssignee) {
        String result = approvalFormService.remind(formID, targetAssignee);
        log.info("【调用工作流催办接口】响应正文：" + result);
    }

    @Override
    @Transactional
    public String create(JournalDropoutCreateDTO params) {
        String studentRecordId = params.getStudentRecordId();
        StudentRecord studentRecord = this.getAndcheckDropoutStudentRecord(studentRecordId);

        JournalDropout journalDropout = new JournalDropout();
        BeanUtils.copyProperties(params, journalDropout);
        journalDropout.setState(Boolean.TRUE.equals(params.getDraftFlag()) ? JournalStateEnum.DRAFT.name() : JournalStateEnum.PENDING.name());
        if (params.getAmount() != null) {
            Integer amount = BigDecimalUtil.bigDecimalToCentInt(params.getAmount().setScale(2, RoundingMode.HALF_UP));
            journalDropout.setAmount(amount);
            studentRecordService.validateAmount(studentRecord, amount, journalDropout.getState());
        } else {
            journalDropout.setAmount(0);
        }

        journalDropout.setId(bizNumberService.next(BizNumberTypeEnum.JOURNAL_DROPOUT));
        journalDropout.setClazzId(studentRecord.getClazzId());
        journalDropout.setClazzName(studentRecord.getClazzName());
        journalDropout.setType(params.getType().name());
        journalDropout.setCreatedBy(AccountHolder.getRequiredAccountInfo().getEmail());

        // 退学结算
        settlementCalculatorRefund(studentRecordId, params.getBizDate().toLocalDate(), params.getType().name(), journalDropout);

        // 退学原因说明
        if (StringUtils.hasText(params.getReasonCode())) {
            String reasonDescription = dictionaryService.getNameByParentCode(DICT_DROPOUT_REASON, params.getReasonCode());
            Assert.notBlank(reasonDescription, "退学原因错误！");
            journalDropout.setReasonDescription(reasonDescription);
        }

        // 所属公司名称
        if (StringUtils.hasText(params.getCompanyCode())) {
            String companyName = dictionaryService.getNameByParentCode(DICT_DROPOUT_COMPANY, params.getCompanyCode());
            journalDropout.setCompanyName(companyName);
        }

        if (!StringUtils.hasText(journalDropout.getRemark())) {
            journalDropout.setRemark("");
        }

        // 退费金额 用户录入不做计算
        // 添加退学凭单
        int insert = baseMapper.insert(journalDropout);
        Assert.isTrue(insert > 0, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.DROPOUT_SAVE_FAILED));

        if (Boolean.FALSE.equals(params.getDraftFlag())) {
            // 启动审批流程
            this.startProcess(journalDropout);
        }

        return journalDropout.getId();
    }

    /**
     * 功能描述：获取退学学籍信息并校验其退学有效性
     *
     * @param studentRecordId 退学学籍ID
     * @return 退学学籍信息
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2024年3月31日
     */
    private StudentRecord getAndcheckDropoutStudentRecord(String studentRecordId) {
        Assert.notBlank(studentRecordId, StudentRecordErrorBodyEnum.DROPOUT_STUDENT_RECORD_NOT_EXISTS.getMessage());
        StudentRecord studentRecord = studentRecordService.getById(studentRecordId);

        /**
         * 校验退学学籍
         */

        // 学籍必须存在
        Assert.notNull(studentRecord, BizExceptionProducer.produce(StudentRecordErrorBodyEnum.DROPOUT_STUDENT_RECORD_NOT_EXISTS));
        // 学籍没有被锁定
        Assert.isTrue(!studentRecord.getLockFlag(), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.STUDENT_RECORD_LOCKED, studentRecordId));
        // 学籍状态应为已生效状态
        Assert.isTrue(StudentRecordStateEnum.VALID.name().equalsIgnoreCase(studentRecord.getState()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.DROPOUT_STUDENT_RECORD_INVALID));
        // 学籍没有出班
        Assert.isTrue(Objects.isNull(studentRecord.getSettlementDate()), BizExceptionProducer.produce(StudentRecordErrorBodyEnum.DROPOUT_STUDENT_RECORD_ALREADY_SETTLEMENT));

        return studentRecord;
    }
}
